// Code from forum post Dec 12, 2007
//



#define icpPin 8  // ICP input pin on arduino 
//#define one_time_max  475 // these values are setup for NTSC video
//#define one_time_min  300 // PAL would be around 1000 for 0 and 500 for 1
//#define zero_time_max 875 // 80bits times 29.97 frames per sec
//#define zero_time_min 700 // equals 833 (divide by 8 clock pulses)

#define one_time_max          588//581//588 // these values are setup for NTSC video
#define one_time_min          422//400//422 // PAL would be around 1000 for 0 and 500 for 1
#define zero_time_max          1080//1024//1080 // 80bits times 29.97 frames per sec
#define zero_time_min          922//750//922 // equals 833 (divide by 8 clock pulses)

#define end_data_position 63
#define end_sync_position 77
#define end_smpte_position  80

volatile unsigned int pin = 13;
volatile unsigned int bit_time; // volatile instructs the variable to be stored in RAM
volatile boolean valid_tc_word; // booleon can be either of two values true or false
volatile boolean ones_bit_count; // booleon can be either of two values true or false
volatile boolean tc_sync;   // booleon can be either of two values true or false
volatile boolean write_tc_out; // booleon can be either of two values true or false
volatile boolean drop_frame_flag; // booleon can be either of two values true or false

volatile byte total_bits; //this stores a an 8-bit unsigned number
volatile byte current_bit; //this stores a an 8-bit unsigned number
volatile byte sync_count; //this stores a an 8-bit unsigned number

volatile byte tc[8];   //this stores a an 8-bit unsigned number
volatile char timeCode[11]; //this stores a an 8-bit unsigned number
volatile char userBit[10];
long error;
/* ICR interrupt vector */
ISR(TIMER1_CAPT_vect) //ISR=Interrupt Service Routine, and timer1 capture event
{
  //toggleCaptureEdge
  TCCR1B ^= _BV(ICES1); //toggles the edge that triggers the handler so that the duration of both high and low pulses is measured.

  bit_time = ICR1; //this is the value the timer generates
  ///Serial.println(bit_time);
  //resetTimer1
  TCNT1 = 0;

  if ((bit_time < one_time_min) || (bit_time > zero_time_max)) // this gets rid of anything that's not what we're looking for
  {
    //Serial.println(bit_time);
    error++;
    total_bits = 0;
  }
  else
  {
    error = 0;
    if (ones_bit_count == true) // only count the second ones pluse
      ones_bit_count = false;
    else
    {
      if (bit_time > zero_time_min)
      {
        current_bit = 0;
        sync_count = 0;
      }
      else //if (bit_time < one_time_max)
      {
        ones_bit_count = true;
        current_bit = 1;
        sync_count++;
        if (sync_count == 12) // part of the last two bytes of a timecode word
        {
          sync_count = 0;
          tc_sync = true;
          total_bits = end_sync_position;
        }
      }

      if (total_bits <= end_data_position) // timecode runs least to most so we need
      { // to shift things around
        tc[0] = tc[0] >> 1;

        for (int n = 1; n < 8; n++) //creates tc[1-8]
        {
          if (tc[n] & 1)
            tc[n - 1] |= 0x80;

          tc[n] = tc[n] >> 1;
        }

        if (current_bit == 1)
          tc[7] |= 0x80;
      }
      total_bits++;
    }

    if (total_bits == end_smpte_position) // we have the 80th bit
    {
      total_bits = 0;
      if (tc_sync)
      {
        tc_sync = false;
        valid_tc_word = true;
      }
    }

    if (valid_tc_word)
    {
      valid_tc_word = false;

      timeCode[10] = (tc[0] & 0x0F) + 0x30; // frames this converst from binary to decimal giving us the last digit
      timeCode[9] = (tc[1] & 0x03) + 0x30; // 10's of frames this converst from binary to decimal giving us the first digit
      timeCode[8] = ':';
      timeCode[7] = (tc[2] & 0x0F) + 0x30; // seconds
      timeCode[6] = (tc[3] & 0x07) + 0x30; // 10's of seconds
      timeCode[5] = ':';
      timeCode[4] = (tc[4] & 0x0F) + 0x30; // minutes
      timeCode[3] = (tc[5] & 0x07) + 0x30; // 10's of minutes
      timeCode[2] = ':';
      timeCode[1] = (tc[6] & 0x0F) + 0x30; // hours
      timeCode[0] = (tc[7] & 0x03) + 0x30; // 10's of hours

      //drop_frame_flag = bit_is_set(tc[1], 2); //detects whether theree is the drop frame bit.
      drop_frame_flag = (tc[1]&0x04)!=0;

      write_tc_out = true;
    }
  }
}


void setup()
{

  pinMode(icpPin, INPUT);   // ICP pin (digital pin 8 on arduino) as input

  bit_time = 0;
  valid_tc_word = false;
  ones_bit_count = false;
  tc_sync = false;
  write_tc_out = false;
  drop_frame_flag = false;
  total_bits = 0;
  current_bit = 0;
  sync_count = 0;

  //lcd.print("Finished setup");
  delay (1000);

  TCCR1A = B00000000; // clear all
  TCCR1B = B11000010; // ICNC1 noise reduction + ICES1 start on rising edge + CS11 divide by 8
  TCCR1C = B00000000; // clear all
  TIMSK1 = B00100000; // ICIE1 enable the icp

  TCNT1 = 0; // clear timer1
  Serial.begin(115200);
}
byte cup[10];
byte last_cup_num, last_cup_ten, last_frame;
int i, frame;
void loop()
{
  if (write_tc_out)
  {
    write_tc_out = false;


    frame = (timeCode[9] - 48) * 10 + (timeCode[10] - 48);
    if ((abs(last_frame - frame) == 1 || abs(last_frame - frame) == 24) && timeCode[1] <= 0x39 && timeCode[4] <= 0x39 && timeCode[0] == 0x30) //trim data
    {
#ifdef DEBUG_DATA
      for (int i = 0; i < 10; i++)
      {

        Serial.print(timeCode[i], HEX);
        Serial.print(" ");
      }
#endif
      Serial.println((char*)timeCode);

    }
    last_frame = frame;
  }
}
